<!doctype html>
<html>
<head>
<meta charset="utf-8">
<style>
body,td,th{
    font-family:sans-serif;
    font-size:12px;
}
td {
    vertical-align: top;
}


a.sort_link{
    margin-left:10px;
    font-size: 15px;
    text-decoration:none;
}

</style>

<script type="text/javascript" src="../src/brython_builtins.js"></script>
<script type="text/javascript" src="../src/version_info.js"></script>
<script type="text/javascript" src="../src/py2js.js"></script>
<script type="text/javascript" src="../src/loaders.js"></script>
<script type="text/javascript" src="../src/py_object.js"></script>
<script type="text/javascript" src="../src/py_type.js"></script>
<script type="text/javascript" src="../src/py_utils.js"></script>
<script type="text/javascript" src="../src/py_sort.js"></script>
<script type="text/javascript" src="../src/py_builtin_functions.js"></script>
<script type="text/javascript" src="../src/py_exceptions.js"></script>
<script type="text/javascript" src="../src/py_range_slice.js"></script>
<script type="text/javascript" src="../src/py_bytes.js"></script>
<script type="text/javascript" src="../src/py_set.js"></script>
<script type="text/javascript" src="../src/js_objects.js"></script>
<script type="text/javascript" src="../src/stdlib_paths.js"></script>
<script type="text/javascript" src="../src/py_import.js"></script>
<script type="text/javascript" src="../src/unicode_data.js"></script>
<script type="text/javascript" src="../src/py_string.js"></script>
<script type="text/javascript" src="../src/py_int.js"></script>
<script type="text/javascript" src="../src/py_long_int.js"></script>
<script type="text/javascript" src="../src/py_float.js"></script>
<script type="text/javascript" src="../src/py_complex.js"></script>
<script type="text/javascript" src="../src/py_dict.js"></script>
<script type="text/javascript" src="../src/py_list.js"></script>
<script type="text/javascript" src="../src/py_generator.js"></script>
<script type="text/javascript" src="../src/py_dom.js"></script>

<script type="text/javascript" src="../src/builtin_modules.js"></script>
<script type="text/javascript" src="../src/py_import_hooks.js"></script>
<script type="text/javascript" src="../src/async.js"></script>

<script type="text/python" src="show_source.py"></script>

</head>
<body onLoad="brython(1)">

<table width="100%">
<tr>
<td width="25%" style="padding-left:3%;">
    <h2>Web Component</h2>
    This example shows how to create custom HTML tags using the standard DOM
    <a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements"
        target="_blank">Web Component</a> technology.

</td>
<td id="right">

<h1>Pop-up info widget</h1>

<form>
  <div>
    <label for="cvc">Enter your CVC
        <popup-info img="img/alt.png"
            data-text="Your card validation code (CVC) is an extra security feature — it is the last 3 or 4 numbers on the back of your card.">
        </popup-info>
    </label>
    <input type="text" id="cvc">
    <p>
    <bold-italic data-val="hello"></bold_italic>
  </div>
</form>

<child-component data="initial" id="child"></child-component>

<p style="margin-top: 5em;">Change attribute value <button id="change_data">change</button>

<ui-page></ui-page>

</td>
</tr>
</table>


<script type="text/python">
from browser import bind, document, window, html, webcomponent
import javascript

style_str = """
  .wrapper {
    position: relative;
  }
  .info {
    font-size: 0.8rem;
    width: 200px;
    display: inline-block;
    border: 1px solid black;
    padding: 10px;
    background: white;
    border-radius: 10px;
    opacity: 0;
    transition: 0.6s all;
    position: absolute;
    top: 20px;
    left: 10px;
    z-index: 3;
  }
  img {
    width: 1.2rem;
  }
  .icon:hover + .info, .icon:focus + .info {
    opacity: 1;
  }
"""

class PopUpInfo:

    def __init__(self):
        # Create a shadow root
        shadow = self.attachShadow({'mode': 'open'})

        # Create spans
        wrapper = html.SPAN(Class="wrapper")

        info = html.SPAN(Class="info")
        # Take attribute content and put it inside the info span
        text = self.attrs['data-text']
        info.textContent = text

        # Insert icon
        icon = html.SPAN(Class="icon", tabindex=0)

        if self.hasAttribute('img'):
            imgUrl = self.getAttribute('img')
        else:
            imgUrl = 'img/default.png'

        img = html.IMG(src=imgUrl)
        icon <= img

        style = html.STYLE()
        style.textContent = style_str

        shadow <= style
        shadow <= wrapper
        wrapper <= icon
        print("info", info)
        wrapper <= info

    def connectedCallback(self):
        print("PopUpInfo connected callback", self)

webcomponent.define("popup-info", PopUpInfo)

class BoldItalic:

    def __init__(self):
        # Create a shadow root
        shadow = self.attachShadow({'mode': 'open'})

        # Insert the value of attribute "data-val" in bold italic
        # in the shadow root
        shadow <= html.B(html.I(self.attrs['data-val']))

webcomponent.define("bold-italic", BoldItalic)


class Parent:

    def __init__(self):
        self.shadow = self.attachShadow({'mode': 'open'})
        self.shadow <= html.B('parent component') + html.BR()

class Child(Parent):

    nb_cx = 0

    def __init__(self):
        super().__init__()
        self.shadow <= html.B('child component')
        assert type(self) is Child
        assert self.__class__ is Child
        assert isinstance(self, Child)

    def connectedCallback(self):
        print(self, "connected")
        Child.nb_cx += 1

    def observedAttributes(self):
        return ["data"]

    def attributeChangedCallback(self, name, old, new, ns):
        print(f"attribute {name} changed from {old} to {new}")

webcomponent.define("parent-component", Parent)
webcomponent.define("child-component", Child)
assert Child.nb_cx == 1

@bind("#change_data", "click")
def change_data(ev):
    document["child"].attrs["data"] = "new"

observed_tag = html.maketag("observed-element")

class Observed:

    def observedAttributes(self):
        return ["data"]

    def attributeChangedCallback(self, name, old, new, ns):
        print(f"attribute {name} changed from {old} to {new}")

webcomponent.define("observed-element", Observed)

elt = observed_tag()
document <= elt
elt.attrs["data"] = "info"

class BaseComponent:

    _registry = []

    @classmethod
    def __init_subclass__(cls, **kwargs):
        super().__init_subclass__(**kwargs)
        BaseComponent._registry.append(cls)

    @staticmethod
    def un_camel(word: str) -> str:
        upper_chars: str = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
        last_char: str = word[0]
        output: list = [last_char.lower()]
        for c in word[1:]:
            if c == "_":
                output.append("-")
                continue
            if c in upper_chars:
                if last_char not in upper_chars:
                    output.append('-')
                output.append(c.lower())
            else:
                output.append(c)
            last_char = c
        return "".join(output)

    @classmethod
    def register(cls):
        registry = cls._registry
        for web_component in registry:
            web_component_name = cls.un_camel(web_component.__name__)
            component_name = f"ui-{web_component_name}"
            webcomponent.define(component_name, web_component)


class Page(BaseComponent):

    _ignore_list = ["UI-PAGE-CONTENT", "UI-TOOLBAR"]

    def connectedCallback(self):
        self.test()
        assert self.test_static(2) == 4
        print("tests for Page class ok")

    def test(self):
        assert self._ignore_list == ["UI-PAGE-CONTENT", "UI-TOOLBAR"]

    @staticmethod
    def test_static(x):
        return x * 2

BaseComponent.register()
</script>

</body>
</html>
